home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fritz: All Fritz
/
All Fritz.zip
/
All Fritz
/
FILES
/
MUSIUSIC
/
MIDICOLL.LZH
/
MIDISTUF.ARC
/
MPUPRO.TXT
< prev
next >
Wrap
Text File
|
1986-08-22
|
73KB
|
2,094 lines
####################################################################
The text following is six separate program files, three each for two
separate programs. They are separated by a line of "###'s" and must
be each culled out of this file before assembly or compilation. The
first three files are "MPRIM.ASM", "MPU.H", and "TESTMPU.C". These
comprise the beginning of an interrupt driven program using the
Roland MPU-401 in its "intelligent" mode. This might be assumed to
be the best mode for writing sequencer and recorder programs,
especially if memory resources are limited. There is a drawback in
this mode, in that any software written for it becomes chained to
usage with the MPU. If you have an eye to transporting your work to
such as the Arari/ST, this is not so good. Also, while the MPU is
impressive, it was designed to be memory efficient when used as the
foundation for a sequencer/recorder. If you are looking to set up
musical phrases as, say LISP s-expressions, it might not be so great.
For these two reasons, and for others I haven't thought of, you might
want to put the MPU to sleep, and just use it as a dumb MIDI port.
The second three program files do just that. They are "MIDI.ASM",
"MIDI.H", and "TESTMIDI.C" All were written for the Microsoft
Assembler version 3 or higher, and the Microsoft C compiler, version
4 (the new one). Both resulting programs do work on my Kaypro 286i
(an AT-clone). They may or may not work on your machine. I have
left the copyright notice intact because I wish to emphasize that
these programs are suitable only for pointing other MPU programmers
in the right direction. There are dead ends and (likely) errors.
Used with caution as a guide to your own programs, they might be
usefull. Used without thought or understanding, and I guarantee they
will be more trouble than they are worth. With that cheery thought,
I wish you good luck.
John Dunn
January, 1986
###############################################################
PAGE 60,127
TITLE MPU primitives
NAME MPRIM
.SALL
;==============================================================
; COPYRIGHT (C) 1986 John Dunn
;--------------------------------------------------------------
; date: 01/02/86
; update: 01/02/86
; last hacker: John Dunn
;==============================================================
PRIM_TEXT SEGMENT BYTE PUBLIC 'CODE'
PRIM_TEXT ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
DGROUP GROUP CONST, _BSS, _DATA
;==============================================================
_DATA SEGMENT WORD PUBLIC 'DATA'
;--------------------------------------------------------------
PUBLIC _indexp,_indext,_channel,_rtmsg,_pending
PUBLIC _recording,_playing,_loading,_enderr
;--------------------------------------------------------------
_channel dw 0 ; current midi channel
_rtmsg dw 0 ; real time message flag
_pending dw 0 ; number of sys excl pending
_recording dw 0 ; nz when recording track data
_playing dw 0 ; nz when playing track data
_loading dw 0 ; nz when loading para data
_enderr dw 0 ; nz if put index at limit
_indext dw 0 ; index track buffer
_indexp dw 0 ; index param buffer
startt dw 0 ; start track buffer
startp dw 0 ; start param buffer
endtrk dw 0 ; end track buffer
endpar dw 0 ; end param buffer
limitt dw tbufx-_tbuf ; track buffer limit
limitp dw pbufx-_pbuf ; param buffer limit
icount dw 0 ; midi msg count index
rcount dw 0 ; midi msg run count
pcount dw 0 ; play track count
clkblp dw 0 ; clock blip count
intval dw 0 ; inte data value
special dw 0 ; nz = special routine
sptable dw dotimev,procsm,sysexc,songsel,songp1,songp2
;--------------------------------------------------------------
_DATA ENDS
;==============================================================
PBUF_DATA SEGMENT PARA MEMORY 'BUFFER'
;--------------------------------------------------------------
PUBLIC _pbuf
;--------------------------------------------------------------
_pbuf db 17000 dup(?) ; parameter buffer
pbufx db 0
;--------------------------------------------------------------
PBUF_DATA ENDS
;==============================================================
TBUF_DATA SEGMENT PARA MEMORY 'BUFFER'
;--------------------------------------------------------------
PUBLIC _tbuf
;--------------------------------------------------------------
_tbuf db 16384 dup(?) ; parameter buffer
tbufx db 0
;--------------------------------------------------------------
TBUF_DATA ENDS
;==============================================================
PRIM_TEXT SEGMENT
ASSUME CS: PRIM_TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
;==============================================================
bpo equ 6 ; base pointer offset
; 6 = large model; 4 = small
p1 equ bpo ; single word arg 1, use [bp+@1]
p2 equ bpo+2 ; single word arg 2, use [bp+@2]
;--------------------------------------------------------------
mdata equ 0330H ; mpu data port address
mstat equ 0331H ; mpu status port address
mcmd equ 0331H ; mpu command port address
mdsr equ 80H ; mpu data set ready, active low
mdrr equ 40H ; mpu data read ready, active low
;--------------------------------------------------------------
; initialize mpu, int vectors, etc.
; must be called once only on startup
;
public _initm
_initm proc far
push es ; save current es
mov ah,35h ; get current int 2
mov al,0AH
int 21H
mov word ptr cs:orgint+3,es ; save it
mov word ptr cs:orgint+1,bx
pop es ; restore es
push ds ; save current ds
mov ah,25H ; set int vect
mov al,0AH ; int 2 for MPU
mov dx,seg mpuint
mov ds,dx
mov dx,offset mpuint
int 21H ; set new int vect
pop ds ; restore ds
mov dx,mdata ; clear data port
in al,dx
in al,21H ; enable irq2
jmp short $+2 ; delay for AT
and al,0FBH
out 21H,al
sti ; enable ints
ret
_initm endp ; end of init mpu
;--------------------------------------------------------------
; shutdown mpu, restore int vectors, etc.
; must be called once only on exit
;
public _exitm
_exitm proc far
in al,21H ; disable irq2
jmp short $+2 ; delay for AT
or al,4
out 21H,al
push ds
mov ah,25h ; restore previous irq2
mov al,0AH
mov dx,word ptr cs:orgint+3
mov ds,dx
mov dx,word ptr cs:orgint+1
int 21h
pop ds
ret
_exitm endp
;--------------------------------------------------------------
; this routine is only called by int 2
; if it was not generated by the mpu, it vectors
; to the original int address, otherwise it saves
; registers, then calls the c routine _mpuint,
; after which it restores registers, clears nmi
; and returns from int.
;
mpuint proc far
push ax ; save ax
push dx
mov dx,mstat ; read mpu status
mpui0: jmp short $+2
in al,dx
and al,mdsr ; generated by mpu?
jz mpui1 ; yes, branch
; jmp mpui0
pop dx ; no, restore cpu
pop ax
iret ; return from interrupt
orgint: jmp far ptr intval ; dummy vector, filled by _initm
dw 0
mpui1:
push bx ; save cpu state
push cx
push di
push si
push bp
push ds
push es
mov ax,seg dgroup ; set up c seg regs
mov ds,ax
mov es,ax
mov dx,mdata ; get mpu int data
in al,dx
call dompu ; do the mpu routine
pop es ; restore seg regs
pop ds
pop bp ; restore cpu state
pop si
pop di
pop cx
pop bx
pop dx
mov al,20H ; send eoi to 8259
out 20H,al
pop ax
iret ; return from interrupt
mpuint endp
;--------------------------------------------------------------
; dompu
; process mpu inte
; local call
;
dompu proc near
mov byte ptr intval,al ; save as global variable
mov bx,special
or bx,bx ; special flag set?
jz dompu1 ; no, branch
dec bx ; yes, jump to special routine
add bx,bx
mov dx,sptable[bx]
jmp dx
dompu1: cmp al,0F0H ; < F0H
jnb dompu2 ; no, branch
jmp timev ; yes, do time value
dompu2: cmp al,0F8H ; < F8H
jnb dompu3 ; no, branch
jmp trackd ; yes, do track data request
dompu3: jnz dompu4 ; branch if not = F8H
jmp timeo ; else do timing overflow
dompu4: cmp al,0F9H ; = F9?
jnz dompu5 ; no, branch
jmp condr ; yes, do conductor request
dompu5: cmp al,0FDH ; = FD?
jnz dompu6 ; no, branch
jmp clockh ; yes, do clock to host
dompu6: cmp al,0FCH ; = FD?
jnz dompu7 ; no, branch
jmp allend ; yes, do all end
dompu7: cmp al,0FFH ; = FF?
jnz dompu8 ; no, branch
jmp midism ; yes, do midi system message
dompu8: ret
dompu endp
;--------------------------------------------------------------
; mpuput(data)
; send data to mpu-401
; C call
;
public _mpuput
_mpuput proc far
push bp
mov bp,sp
mov dx,mstat ; mpu status port
mpup1: in al,dx ; get the status
and al,mdrr ; test for Data Recieve Ready
jnz mpup1 ; loop til ready
mov dx,mdata ; mpu data port
mov ax,[bp+p1] ; get the data
out dx,al ; send to mpu
mov sp,bp ; restore C sp
pop bp
ret ; exit
_mpuput endp
;--------------------------------------------------------------
; mpuput
; send data in AL to mpu-401
; local call, AX is preserved
;
mpuput proc near
push ax
mov dx,mstat ; mpu status port
mpupa1: in al,dx ; get the status
and al,mdrr ; test for Data Recieve Ready
jnz mpupa1 ; loop til ready
mov dx,mdata ; mpu data port
pop ax ; get the data
out dx,al ; send to mpu
ret ; exit
mpuput endp
;--------------------------------------------------------------
; data=mpuget()
; get data from mpu-401
; C call
;
public _mpuget
_mpuget proc far
mov dx,mstat ; mpu status port
mpug1: in al,dx ; get the status
and al,mdsr ; test for Data Set Ready
jnz mpug1 ; loop til ready
mov dx,mdata ; mpu data port
in al,dx ; get the data byte
mov ah,0 ; zero out ms byte
ret ; exit with ax = data
_mpuget endp
;--------------------------------------------------------------
; mpuget
; get data from mpu-401 to AX
; local call
;
mpuget proc near
mov dx,mstat ; mpu status port
mpuga1: in al,dx ; get the status
and al,mdsr ; test for Data Set Ready
jnz mpuga1 ; loop til ready
mov dx,mdata ; mpu data port
in al,dx ; get the data byte
mov ah,0 ; zero out ms byte
ret ; exit with ax = data
mpuget endp
;--------------------------------------------------------------
; mpucmd(cmd)
; send a command to mpu-401
;
public _mpucmd
_mpucmd proc far
push bp
mov bp,sp
mov dx,mstat ; mpu status port
mpuc1: in al,dx ; get the status
and al,mdrr ; test for Data Recieve Ready
jnz mpuc1 ; loop til ready
cli ; disable intes
mov ax,[bp+p1] ; get the command
out dx,al ; send to mpu
mpuc2: in al,dx ; get the status
and al,mdsr ; test for Data Set Ready
jnz mpuc2 ; loop til ready
mov dx,mdata ; mpu data port
in al,dx ; read it
cmp al,0FEH ; acknowledge?
jz mpuc3 ; yes, branch
push di ; save C registers
push si
call dompu ; do mpu routine
pop si
pop di
mov dx,mstat ; mpu status port
jmp short mpuc2 ; check again for ack
mpuc3: sti ; enable ints
mov sp,bp ; restore C sp
pop bp
ret ; exit
_mpucmd endp
;--------------------------------------------------------------
; data = gett()
; get byte from track buffer
; C call
;
public _gett
_gett proc far
mov bx,_indext ; get index
mov dx,seg _tbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endtrk ; reached end?
jnz gett1 ; no, exit
mov bx,startt ; yes, set index = start
gett1: mov _indext,bx ; save index
ret ; exit with ax = data
_gett endp
;--------------------------------------------------------------
; gett
; get byte to AX from track buffer
; local call
;
gett proc near
mov bx,_indext ; get index
mov dx,seg _tbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endtrk ; reached end?
jnz getta1 ; no, exit
mov bx,startt ; yes, set index = start
getta1: mov _indext,bx ; save index
ret ; exit with ax = data
gett endp
;--------------------------------------------------------------
; putt(track_data)
; put byte to track buffer
; C call
;
public _putt
_putt proc far
push bp
mov bp,sp
mov bx,_indext ; get index
mov dx,seg _tbuf
mov al,[bp+p1] ; get the data
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitt ; reached limit?
mov ax,1 ; flag error
jz putt0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indext,bx ; store index
mov endtrk,bx ; end = index
putt0: mov _enderr,ax ; save in _enderr
mov sp,bp ; restore C sp
pop bp
ret ; exit
_putt endp
;--------------------------------------------------------------
; putt
; put byte in AL to track buffer
; local call
;
putt proc near
mov bx,_indext ; get index
mov dx,seg _tbuf
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitt ; reached limit?
mov ax,1 ; flag error
jz putta0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indext,bx ; store index
mov endtrk,bx ; end = index
putta0: mov _enderr,ax ; save in _enderr
ret ; exit
putt endp
;--------------------------------------------------------------
; data = getp()
; get byte from parameter buffer
; C call
;
public _getp
_getp proc far
mov bx,_indexp ; get index
mov dx,seg _pbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endpar ; reached end?
jnz getp1 ; no, exit
mov bx,startp ; yes, set index = start
getp1: mov _indexp,bx ; save index
ret ; exit with ax = data
_getp endp
;--------------------------------------------------------------
; getp
; get byte to AX from param buffer
; local call
;
getp proc near
mov bx,_indexp ; get index
mov dx,seg _pbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endpar ; reached end?
jnz getpa1 ; no, exit
mov bx,startp ; yes, set index = start
getpa1: mov _indexp,bx ; save index
ret ; exit with ax = data
getp endp
;--------------------------------------------------------------
; putp(param_data)
; put byte to param buffer
; C call
;
public _putp
_putp proc far
push bp
mov bp,sp
mov bx,_indexp ; get index
mov dx,seg _pbuf
mov al,[bp+p1] ; get the data
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitp ; reached limit?
mov ax,1 ; flag error
jz putp0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indexp,bx ; store index
mov endpar,bx ; end = index
putp0: mov _enderr,ax ; save in _enderr
mov sp,bp ; restore C sp
pop bp
ret ; exit
_putp endp
;--------------------------------------------------------------
; putp
; put byte in AL to param buffer
; local call
;
putp proc near
mov bx,_indexp ; get index
mov dx,seg _pbuf
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitp ; reached limit?
mov ax,1 ; flag error
jz putpa0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indexp,bx ; store index
mov endpar,bx ; end = index
putpa0: mov _enderr,ax ; save in _enderr
ret ; exit
putp endp
;--------------------------------------------------------------
; timeo
; process timing overflow on inte
; local call with intval in AL
;
timeo proc near
call putt
ret
timeo endp
;--------------------------------------------------------------
; condr
; process conductor request on inte
; local dummy routine, sends timing overflow byte
;
condr proc near
mov al,0F8H
call putt
ret
condr endp
;--------------------------------------------------------------
; clockh
; process clock to host on inte
; local call
;
clockh proc near
mov ax,clkblp ; get blip flag
inc ax ; count up
and ax,1
mov clkblp,ax ; put back
inc ax ; 1,2 = happy face
mov cx,ds
mov dx,0B800H ; point to gx screen
mov ds,dx
mov byte ptr ds:9EH,al ; display blip
mov ds,cx
ret
clockh endp
;--------------------------------------------------------------
; allend
; process all end on inte
; local call, clears playing flag
;
allend proc near
mov ax,0
mov _playing,ax
ret
allend endp
;--------------------------------------------------------------
; timev
; process time value on inte
; local call with intval in AL
;
timev proc near
call putt
mov ax,1 ; set special = 1
mov special,ax ; dotimev on next inte
ret
timev endp
;--------------------------------------------------------------
; dotimev (special = 1 )
; next inte processing of time value
; local call with intval in AL
;
dotimev proc near
cmp al,0F8H ; mpu mark, no operation
jz dotime1
cmp al,0F9H ; mpu mark, measure end
jz dotime2
cmp al,0FCH ; mpu mark, data end
jnz dotime3
mov ax,0
mov _recording,ax ; clr recording flag
dotime2:call putt ; put in record buffer
dotime1:mov ax,0
mov special,ax ; done, clear special
ret ; exit
dotime3:mov ah,al ; get a copy
and ah,0F0H ; zip channel data
cmp ah,0C0H ; midi msg, program change
jz dotime4
cmp ah,0DH ; midi msg, channel pressure
jnz dotime5
dotime4:mov dx,1 ; set to recieve 1 more byte
jmp short dotime6
dotime5:cmp ah,80H ; midi msg, note off
jz dotime7
cmp ah,90H ; midi msg, note on
jz dotime7
cmp ah,0A0H ; midi msg, after touch
jz dotime7
cmp ah,0B0H ; midi msg, control change
jz dotime7
cmp ah,0E0H ; midi msg, pitch wheel
jnz dotime8
dotime7:mov dx,2 ; set to recieve 2 more bytes
dotime6:mov rcount,dx
mov icount,dx
call putt ; put in record buffer
ret ; exit
dotime8:and ah,80H ; < 7FH ?
jz dotime9 ; yes, branch
mov ax,0 ; no, is error
mov special,ax ; clear special
call far ptr _beep ; signal error
ret ; exit
dotime9:mov ah,byte ptr icount ; get current count
cmp ah,0 ; new one?
jnz dotim10 ; no, branch
mov ah,byte ptr rcount ; yes, icount <-- rcount
dotim10:push ax ; save it
call putt ; save the data byte in AL
pop ax ; ah = icount
dec ah ; dec icount
mov byte ptr icount,ah ; save it
jnz dotime11 ; branch if icount not 0
mov ax,0 ; else clear special
mov special,ax
dotime11:ret ; exit
dotimev endp
;--------------------------------------------------------------
; trackd
; process track play request on inte
; local call with intval in AL
;
trackd proc near
call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
cmp al,0F8H ; midi timing overflow
jnz trackd1
ret ; just exit if it was timing overfow
trackd1:call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
and al,0F0H ; strip midi channel info
cmp al,0F0H ; mpu mark
jnz trackd2
ret
trackd2:test al,80H ; <= 7FH ?
jnz trackd3 ; no, branch
cmp pcount,1 ; pcount = 1 ?
jnz trackd4 ; no, branch
ret ; yes, exit
trackd3:cmp al,0C0H ; one byte needed?
jz trackd5
cmp al,0D0H
jnz trackd6
trackd5:mov pcount,1 ; yes, set running pcount to 1
jmp short trackd4 ; ... and get one more byte
trackd6:mov pcount,2 ; else set running pcount to 2
call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
trackd4:call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
ret
trackd endp
;--------------------------------------------------------------
; midism
; process midi system message on inte
; local call
;
midism proc near
mov ax,2 ; flag special = 2
mov special,ax ; procsm on next inte
ret
midism endp
;--------------------------------------------------------------
; procsm ( special = 2)
; continue to process midi system message in inte
; local call with intval in AL
;
procsm proc near
cmp al,0F0H ; midi exclusive
jnz procsm1
call putp ; save in para buffer
mov ax,1 ; set loading flag
mov _loading,ax
mov ax,3 ; set special = 3
mov special,ax ; continue on next inte
ret
procsm1:cmp al,0F3H ; song select
jnz procsm2
mov ax,4 ; set special = 4
mov special,ax ; continue on next inte
ret
procsm2:cmp al,0F2H ; song position
jnz procsm3
mov ax,5 ; set special = 5
mov special,ax ; continue on next inte
ret
procsm3:cmp al,0F6H ; tune request
jnz procsm4
nop ; insert routine here
jmp short procsm0 ; clr special & exit
procsm4:mov byte ptr _rtmsg,al ; flag real time message
procsm0:mov ax,0 ; clear special
mov special,ax
ret ; exit
procsm endp
;--------------------------------------------------------------
; sysexc (special = 3 )
; inte processing of system exclusive values
; local call with intval in AL
;
sysexc proc near
push ax ; save inte value
call putp ; save in parameter buffer
pop ax
cmp al,0F7H ; was it EOX
jnz sysexc0 ; no, just exit
mov ax,0 ; yes,
mov _loading,ax ; clear loading flag
mov special,ax ; clear special
inc word ptr _pending ; inc pending flag
sysexc0:ret ; exit
sysexc endp
;--------------------------------------------------------------
; songsel (special = 4)
; inte processing of song select
; local call with intval in AL
;
songsel proc near
nop ; dummy routine
mov ax,0 ; clear special
mov special,ax
ret
songsel endp
;--------------------------------------------------------------
; songp1 (special = 5)
; inte processing of song position 1st byte
; local call with intval in AL
;
songp1 proc near
nop ; dummy routine
mov ax,6 ; special = 6
mov special,ax ; songp2 on next int
ret
songp1 endp
;--------------------------------------------------------------
; songp2 (special = 6)
; inte processing of position 2nd byte
; local call with intval in AL
;
songp2 proc near
nop ; dummy routine
mov ax,0 ; clear special
mov special,ax
ret
songp2 endp
;--------------------------------------------------------------
; a little beep on the speaker
;
public _beep
_beep proc far
mov al,0b6h
out 043h,al ;write timer mode regester
mov ax,1000 ;set divisor value to 1000
out 042h,al ;write timer 1 count lsb
mov al,ah
out 042h,al ;write timer 2 count msb
in al,061h ;get current port b setting
mov ah,al ;save current setting.
or al,3 ;turn speaker on
out 061h,al
mov cx,0a48h ;10 msec delay on ibm pc 4.7mh 8088
delay:
loop delay
mov al,ah ;get old port b setting
out 061h,al ;set it back the way you found it
ret
_beep endp
;--------------------------------------------------------------
; blip(char) -- sends char to upper right corner of screen
;
public _blip
_blip proc far
push bp
mov bp,sp
mov ax,[bp+p1]
add ax,'0'
mov cx,ds
mov dx,0B800H
mov ds,dx
mov byte ptr ds:9EH,al
mov ds,cx
mov sp,bp
pop bp
ret
_blip endp
;--------------------------------------------------------------
PRIM_TEXT ENDS
END
###############################################################
/**************************************************************
* mpu.h
*
* equates for mpu & tx816
*
*/
/* mpu port addresses & flags
*/
#define MDATA 0x330 /* mpu data port address */
#define MSTAT 0x331 /* mpu status port address */
#define MCMD 0x331 /* mpu command port address */
#define MDSR 0x80 /* mpu data set ready, active low */
#define MDRR 0x40 /* mpu data read ready, active low */
/* mpu data codes
*/
#define NULINT 0xFA /* null interrupt code */
#define MPUACK 0xFE /* mpu acknowledge */
/* mpu command codes
*/
#define METRONOME_ON 0x83 /* metronome on with no accents */
#define METRONOME_ACCENT 0x85 /* metronome on with accents */
#define METRONOME_OFF 0x84 /* metronome off */
#define RESET 0xFF /* reset mpuw */
#define SEND_SYS 0xDF /* want to send system message */
#define EXCL_ON 0x97 /* exclusive to host: on */
#define EXCL_OFF 0x96 /* exclusive to host: off */
#define CLOCK_ON 0x95 /* clock to host: on */
#define CLOCK_OFF 0x94 /* clock to host: off */
/* midi codes
*/
#define EOX 0xF7 /* end of transmission */
/* Yamaha specific codes
*/
#define DUMP_1V 0 /* bulk dump 1 voice */
#define DUMP_1P 1 /* bulk dump 1 performance setup */
#define DUMP_64P 2 /* bulk dump 64 performance setups */
#define DUMP_32V 9 /* bulk dump 32 voices */
#define DUMP_CA 0 /* dump condition acknowledge */
###############################################################
/**************************************************************
* testmpu.c
*
* test program for mpu & TX816
*
*/
#include "stdio.h"
#include "mpu.h"
/**************************************************************
* global values
*/
extern unsigned char tbuf[]; /* track buffer */
extern unsigned char pbuf[]; /* parameter buffer */
extern unsigned int indext; /* track buf index */
extern unsigned int indexp; /* para buf index */
extern unsigned int channel; /* current midi channel */
extern unsigned int rtmsg; /* real time message flag */
extern unsigned int pending; /* number of sys excl pending */
extern unsigned int recording; /* nz when recording track data */
extern unsigned int playing; /* nz when playing track data */
extern unsigned int loading; /* nz when loading para data */
extern unsigned int enderr; /* nz if put index at limit */
main(argc, argv)
int argc;
char *argv[];
{
int i;
initm();
mpucmd(RESET);
mpucmd(EXCL_ON);
mpucmd(CLOCK_ON);
getchar();
printf("dump in progress\n");
dump_request(DUMP_1V);
for(i = 0; i < 256; ++i)
printf("%x ",pbuf[i]);
printf("\n\n");
mpucmd(RESET);
printf("reset\n");
getchar();
mpucmd(CLOCK_OFF);
exitm();
exit(0);
}
/**************************************************************
* issue a request to dump data
* specific to Yamaha
*/
dump_request(fmt)
int fmt;
{
indexp = 0;
mpucmd(SEND_SYS);
mpuput(0xF0);
mpuput(0x43);
mpuput(0x20 | channel);
mpuput(fmt);
mpuput(EOX);
while(!loading);
beep();
}
###############################################################
PAGE 60,127
TITLE MIDI primitives for dumb-MPU
NAME MIDI
.SALL
;==============================================================
; COPYRIGHT (C) 1986 John Dunn
;--------------------------------------------------------------
; date: 01/02/86
; update: 01/02/86
; last hacker: John Dunn
;==============================================================
PRIM_TEXT SEGMENT BYTE PUBLIC 'CODE'
PRIM_TEXT ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
DGROUP GROUP CONST, _BSS, _DATA
;==============================================================
_DATA SEGMENT WORD PUBLIC 'DATA'
;--------------------------------------------------------------
PUBLIC _indexp,_indext,_channel,_rtmsg,_pending
PUBLIC _recording,_playing,_loading,_enderr
;--------------------------------------------------------------
_channel dw 0 ; current midi channel
_rtmsg dw 0 ; real time message flag
_pending dw 0 ; number of sys excl pending
_recording dw 0 ; nz when recording track data
_playing dw 0 ; nz when playing track data
_loading dw 0 ; nz when loading para data
_enderr dw 0 ; nz if put index at limit
_indext dw 0 ; index track buffer
_indexp dw 0 ; index param buffer
startt dw 0 ; start track buffer
startp dw 0 ; start param buffer
endtrk dw 0 ; end track buffer
endpar dw 0 ; end param buffer
limitt dw tbufx-_tbuf ; track buffer limit
limitp dw pbufx-_pbuf ; param buffer limit
icount dw 0 ; midi msg count index
rcount dw 0 ; midi msg run count
pcount dw 0 ; play track count
clkblp dw 0 ; clock blip count
intval dw 0 ; inte data value
special dw 0 ; nz = special routine
sptable dw dotimev,procsm,sysexc,songsel,songp1,songp2
;--------------------------------------------------------------
_DATA ENDS
;==============================================================
PBUF_DATA SEGMENT PARA MEMORY 'BUFFER'
;--------------------------------------------------------------
PUBLIC _pbuf
;--------------------------------------------------------------
_pbuf db 17000 dup(?) ; parameter buffer
pbufx db 0
;--------------------------------------------------------------
PBUF_DATA ENDS
;==============================================================
TBUF_DATA SEGMENT PARA MEMORY 'BUFFER'
;--------------------------------------------------------------
PUBLIC _tbuf
;--------------------------------------------------------------
_tbuf db 16384 dup(?) ; parameter buffer
tbufx db 0
;--------------------------------------------------------------
TBUF_DATA ENDS
;==============================================================
PRIM_TEXT SEGMENT
ASSUME CS: PRIM_TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
;==============================================================
bpo equ 6 ; base pointer offset
; 6 = large model; 4 = small
p1 equ bpo ; single word arg 1, use [bp+@1]
p2 equ bpo+2 ; single word arg 2, use [bp+@2]
;--------------------------------------------------------------
mdata equ 0330H ; mpu data port address
mstat equ 0331H ; mpu status port address
mcmd equ 0331H ; mpu command port address
mdsr equ 80H ; mpu data set ready, active low
mdrr equ 40H ; mpu data read ready, active low
;--------------------------------------------------------------
; initialize mpu, int vectors, etc.
; must be called once only on startup
;
public _initm
_initm proc far
push es ; save current es
mov ah,35h ; get current int 2
mov al,0AH
int 21H
mov word ptr cs:orgint+3,es ; save it
mov word ptr cs:orgint+1,bx
pop es ; restore es
push ds ; save current ds
mov ah,25H ; set int vect
mov al,0AH ; int 2 for MPU
mov dx,seg mpuint
mov ds,dx
mov dx,offset mpuint
int 21H ; set new int vect
pop ds ; restore ds
call mpurst ; reset mpu
in al,21H ; enable irq2
jmp short $+2 ; delay for AT
and al,0FBH
out 21H,al
ret
_initm endp ; end of init mpu
;--------------------------------------------------------------
; shutdown mpu, restore int vectors, etc.
; must be called once only on exit
;
public _exitm
_exitm proc far
in al,21H ; disable irq2
jmp short $+2 ; delay for AT
or al,4
out 21H,al
push ds
mov ah,25h ; restore previous irq2
mov al,0AH
mov dx,word ptr cs:orgint+3
mov ds,dx
mov dx,word ptr cs:orgint+1
int 21h
pop ds
ret
_exitm endp
;--------------------------------------------------------------
; mpurst
; reset the mpu
; local call
;
mpurst proc near
cli ; disable intes
mov dx,mstat ; mpu status port
mpurs1: in al,dx ; get the status
and al,mdrr ; test for Data Recieve Ready
jnz mpurs1 ; loop til ready
mov ax,0FFH ; get the command
out dx,al ; send to mpu
mpurs2: in al,dx ; get the status
and al,mdsr ; test for Data Set Ready
jnz mpurs2 ; loop til ready
mov dx,mdata ; read mpu data port
mov dx,mdata ; read mpu data port
mov dx,mdata ; read mpu data port
sti ; enable intes
ret ; exit
mpurst endp
;--------------------------------------------------------------
; this routine is only called by int 2
; if it was not generated by the mpu, it vectors
; to the original int address, otherwise it saves
; registers, then calls the c routine _mpuint,
; after which it restores registers, clears nmi
; and returns from int.
;
mpuint proc far
push ax ; save ax
push dx
mov dx,mstat ; read mpu status
mpui0: jmp short $+2
in al,dx
and al,mdsr ; generated by mpu?
jz mpui1 ; yes, branch
pop dx ; no, restore cpu
pop ax
iret ; return from interrupt
orgint: jmp far ptr intval ; dummy vector, filled by _initm
dw 0
mpui1:
push bx ; save cpu state
push cx
push di
push si
push bp
push ds
push es
mov ax,seg dgroup ; set up c seg regs
mov ds,ax
mov es,ax
mov dx,mdata ; get mpu int data
in al,dx
call dompu ; do the mpu routine
pop es ; restore seg regs
pop ds
pop bp ; restore cpu state
pop si
pop di
pop cx
pop bx
pop dx
mov al,20H ; send eoi to 8259
out 20H,al
pop ax
iret ; return from interrupt
mpuint endp
;--------------------------------------------------------------
; dompu
; process mpu inte
; local call
;
dompu proc near
mov byte ptr intval,al ; save as global variable
mov bx,special
or bx,bx ; special flag set?
jz dompu1 ; no, branch
dec bx ; yes, jump to special routine
add bx,bx
mov dx,sptable[bx]
jmp dx
dompu1: cmp al,0F0H ; < F0H
jnb dompu2 ; no, branch
jmp timev ; yes, do time value
dompu2: cmp al,0F8H ; < F8H
jnb dompu3 ; no, branch
jmp trackd ; yes, do track data request
dompu3: jnz dompu4 ; branch if not = F8H
jmp timeo ; else do timing overflow
dompu4: cmp al,0F9H ; = F9?
jnz dompu5 ; no, branch
jmp condr ; yes, do conductor request
dompu5: cmp al,0FDH ; = FD?
jnz dompu6 ; no, branch
jmp clockh ; yes, do clock to host
dompu6: cmp al,0FCH ; = FD?
jnz dompu7 ; no, branch
jmp allend ; yes, do all end
dompu7: cmp al,0FFH ; = FF?
jnz dompu8 ; no, branch
jmp midism ; yes, do midi system message
dompu8: ret
dompu endp
;--------------------------------------------------------------
; mpuput(data)
; send data to mpu-401
; C call
;
public _mpuput
_mpuput proc far
push bp
mov bp,sp
mov dx,mstat ; mpu status port
mpup1: in al,dx ; get the status
and al,mdrr ; test for Data Recieve Ready
jnz mpup1 ; loop til ready
mov dx,mdata ; mpu data port
mov ax,[bp+p1] ; get the data
out dx,al ; send to mpu
mov sp,bp ; restore C sp
pop bp
ret ; exit
_mpuput endp
;--------------------------------------------------------------
; mpuput
; send data in AL to mpu-401
; local call, AX is preserved
;
mpuput proc near
push ax
mov dx,mstat ; mpu status port
mpupa1: in al,dx ; get the status
and al,mdrr ; test for Data Recieve Ready
jnz mpupa1 ; loop til ready
mov dx,mdata ; mpu data port
pop ax ; get the data
out dx,al ; send to mpu
ret ; exit
mpuput endp
;--------------------------------------------------------------
; data=mpuget()
; get data from mpu-401
; C call
;
public _mpuget
_mpuget proc far
mov dx,mstat ; mpu status port
mpug1: in al,dx ; get the status
and al,mdsr ; test for Data Set Ready
jnz mpug1 ; loop til ready
mov dx,mdata ; mpu data port
in al,dx ; get the data byte
mov ah,0 ; zero out ms byte
ret ; exit with ax = data
_mpuget endp
;--------------------------------------------------------------
; mpuget
; get data from mpu-401 to AX
; local call
;
mpuget proc near
mov dx,mstat ; mpu status port
mpuga1: in al,dx ; get the status
and al,mdsr ; test for Data Set Ready
jnz mpuga1 ; loop til ready
mov dx,mdata ; mpu data port
in al,dx ; get the data byte
mov ah,0 ; zero out ms byte
ret ; exit with ax = data
mpuget endp
;--------------------------------------------------------------
; mpucmd(cmd)
; send a command to mpu-401
;
public _mpucmd
_mpucmd proc far
push bp
mov bp,sp
mov dx,mstat ; mpu status port
mpuc1: in al,dx ; get the status
and al,mdrr ; test for Data Recieve Ready
jnz mpuc1 ; loop til ready
cli ; disable intes
mov ax,[bp+p1] ; get the command
out dx,al ; send to mpu
mpuc2: in al,dx ; get the status
and al,mdsr ; test for Data Set Ready
jnz mpuc2 ; loop til ready
mov dx,mdata ; mpu data port
in al,dx ; read it
cmp al,0FEH ; acknowledge?
jz mpuc3 ; yes, branch
push di ; save C registers
push si
call dompu ; do mpu routine
pop si
pop di
mov dx,mstat ; mpu status port
jmp short mpuc2 ; check again for ack
mpuc3: sti ; enable ints
mov sp,bp ; restore C sp
pop bp
ret ; exit
_mpucmd endp
;--------------------------------------------------------------
; data = gett()
; get byte from track buffer
; C call
;
public _gett
_gett proc far
mov bx,_indext ; get index
mov dx,seg _tbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endtrk ; reached end?
jnz gett1 ; no, exit
mov bx,startt ; yes, set index = start
gett1: mov _indext,bx ; save index
ret ; exit with ax = data
_gett endp
;--------------------------------------------------------------
; gett
; get byte to AX from track buffer
; local call
;
gett proc near
mov bx,_indext ; get index
mov dx,seg _tbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endtrk ; reached end?
jnz getta1 ; no, exit
mov bx,startt ; yes, set index = start
getta1: mov _indext,bx ; save index
ret ; exit with ax = data
gett endp
;--------------------------------------------------------------
; putt(track_data)
; put byte to track buffer
; C call
;
public _putt
_putt proc far
push bp
mov bp,sp
mov bx,_indext ; get index
mov dx,seg _tbuf
mov al,[bp+p1] ; get the data
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitt ; reached limit?
mov ax,1 ; flag error
jz putt0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indext,bx ; store index
mov endtrk,bx ; end = index
putt0: mov _enderr,ax ; save in _enderr
mov sp,bp ; restore C sp
pop bp
ret ; exit
_putt endp
;--------------------------------------------------------------
; putt
; put byte in AL to track buffer
; local call
;
putt proc near
mov bx,_indext ; get index
mov dx,seg _tbuf
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitt ; reached limit?
mov ax,1 ; flag error
jz putta0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indext,bx ; store index
mov endtrk,bx ; end = index
putta0: mov _enderr,ax ; save in _enderr
ret ; exit
putt endp
;--------------------------------------------------------------
; data = getp()
; get byte from parameter buffer
; C call
;
public _getp
_getp proc far
mov bx,_indexp ; get index
mov dx,seg _pbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endpar ; reached end?
jnz getp1 ; no, exit
mov bx,startp ; yes, set index = start
getp1: mov _indexp,bx ; save index
ret ; exit with ax = data
_getp endp
;--------------------------------------------------------------
; getp
; get byte to AX from param buffer
; local call
;
getp proc near
mov bx,_indexp ; get index
mov dx,seg _pbuf
push ds
mov ds,dx ; fetch the data
mov al,ds:[bx]
xor ah,ah ; ax = data
pop ds
inc bx ; inc index
cmp bx,endpar ; reached end?
jnz getpa1 ; no, exit
mov bx,startp ; yes, set index = start
getpa1: mov _indexp,bx ; save index
ret ; exit with ax = data
getp endp
;--------------------------------------------------------------
; putp(param_data)
; put byte to param buffer
; C call
;
public _putp
_putp proc far
push bp
mov bp,sp
mov bx,_indexp ; get index
mov dx,seg _pbuf
mov al,[bp+p1] ; get the data
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitp ; reached limit?
mov ax,1 ; flag error
jz putp0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indexp,bx ; store index
mov endpar,bx ; end = index
putp0: mov _enderr,ax ; save in _enderr
mov sp,bp ; restore C sp
pop bp
ret ; exit
_putp endp
;--------------------------------------------------------------
; putp
; put byte in AL to param buffer
; local call
;
putp proc near
mov bx,_indexp ; get index
mov dx,seg _pbuf
push ds
mov ds,dx ; store the data
mov ds:[bx],al
pop ds
inc bx ; inc index
cmp bx,limitp ; reached limit?
mov ax,1 ; flag error
jz putpa0 ; yes, branch with err
mov ax,0 ; no, flag no-error
mov _indexp,bx ; store index
mov endpar,bx ; end = index
putpa0: mov _enderr,ax ; save in _enderr
ret ; exit
putp endp
;--------------------------------------------------------------
; timeo
; process timing overflow on inte
; local call with intval in AL
;
timeo proc near
call putt
ret
timeo endp
;--------------------------------------------------------------
; condr
; process conductor request on inte
; local dummy routine, sends timing overflow byte
;
condr proc near
mov al,0F8H
call putt
ret
condr endp
;--------------------------------------------------------------
; clockh
; process clock to host on inte
; local call
;
clockh proc near
mov ax,clkblp ; get blip flag
inc ax ; count up
and ax,1
mov clkblp,ax ; put back
inc ax ; 1,2 = happy face
mov cx,ds
mov dx,0B800H ; point to gx screen
mov ds,dx
mov byte ptr ds:9EH,al ; display blip
mov ds,cx
ret
clockh endp
;--------------------------------------------------------------
; allend
; process all end on inte
; local call, clears playing flag
;
allend proc near
mov ax,0
mov _playing,ax
ret
allend endp
;--------------------------------------------------------------
; timev
; process time value on inte
; local call with intval in AL
;
timev proc near
call putt
mov ax,1 ; set special = 1
mov special,ax ; dotimev on next inte
ret
timev endp
;--------------------------------------------------------------
; dotimev (special = 1 )
; next inte processing of time value
; local call with intval in AL
;
dotimev proc near
cmp al,0F8H ; mpu mark, no operation
jz dotime1
cmp al,0F9H ; mpu mark, measure end
jz dotime2
cmp al,0FCH ; mpu mark, data end
jnz dotime3
mov ax,0
mov _recording,ax ; clr recording flag
dotime2:call putt ; put in record buffer
dotime1:mov ax,0
mov special,ax ; done, clear special
ret ; exit
dotime3:mov ah,al ; get a copy
and ah,0F0H ; zip channel data
cmp ah,0C0H ; midi msg, program change
jz dotime4
cmp ah,0DH ; midi msg, channel pressure
jnz dotime5
dotime4:mov dx,1 ; set to recieve 1 more byte
jmp short dotime6
dotime5:cmp ah,80H ; midi msg, note off
jz dotime7
cmp ah,90H ; midi msg, note on
jz dotime7
cmp ah,0A0H ; midi msg, after touch
jz dotime7
cmp ah,0B0H ; midi msg, control change
jz dotime7
cmp ah,0E0H ; midi msg, pitch wheel
jnz dotime8
dotime7:mov dx,2 ; set to recieve 2 more bytes
dotime6:mov rcount,dx
mov icount,dx
call putt ; put in record buffer
ret ; exit
dotime8:and ah,80H ; < 7FH ?
jz dotime9 ; yes, branch
mov ax,0 ; no, is error
mov special,ax ; clear special
call far ptr _beep ; signal error
ret ; exit
dotime9:mov ah,byte ptr icount ; get current count
cmp ah,0 ; new one?
jnz dotim10 ; no, branch
mov ah,byte ptr rcount ; yes, icount <-- rcount
dotim10:push ax ; save it
call putt ; save the data byte in AL
pop ax ; ah = icount
dec ah ; dec icount
mov byte ptr icount,ah ; save it
jnz dotime11 ; branch if icount not 0
mov ax,0 ; else clear special
mov special,ax
dotime11:ret ; exit
dotimev endp
;--------------------------------------------------------------
; trackd
; process track play request on inte
; local call with intval in AL
;
trackd proc near
call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
cmp al,0F8H ; midi timing overflow
jnz trackd1
ret ; just exit if it was timing overfow
trackd1:call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
and al,0F0H ; strip midi channel info
cmp al,0F0H ; mpu mark
jnz trackd2
ret
trackd2:test al,80H ; <= 7FH ?
jnz trackd3 ; no, branch
cmp pcount,1 ; pcount = 1 ?
jnz trackd4 ; no, branch
ret ; yes, exit
trackd3:cmp al,0C0H ; one byte needed?
jz trackd5
cmp al,0D0H
jnz trackd6
trackd5:mov pcount,1 ; yes, set running pcount to 1
jmp short trackd4 ; ... and get one more byte
trackd6:mov pcount,2 ; else set running pcount to 2
call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
trackd4:call gett ; get next track buffer byte
nop ; fix midi channel
call mpuput ; send it to mpu data port
ret
trackd endp
;--------------------------------------------------------------
; midism
; process midi system message on inte
; local call
;
midism proc near
mov ax,2 ; flag special = 2
mov special,ax ; procsm on next inte
ret
midism endp
;--------------------------------------------------------------
; procsm ( special = 2)
; continue to process midi system message in inte
; local call with intval in AL
;
procsm proc near
cmp al,0F0H ; midi exclusive
jnz procsm1
call putp ; save in para buffer
mov ax,1 ; set loading flag
mov _loading,ax
mov ax,3 ; set special = 3
mov special,ax ; continue on next inte
ret
procsm1:cmp al,0F3H ; song select
jnz procsm2
mov ax,4 ; set special = 4
mov special,ax ; continue on next inte
ret
procsm2:cmp al,0F2H ; song position
jnz procsm3
mov ax,5 ; set special = 5
mov special,ax ; continue on next inte
ret
procsm3:cmp al,0F6H ; tune request
jnz procsm4
nop ; insert routine here
jmp short procsm0 ; clr special & exit
procsm4:mov byte ptr _rtmsg,al ; flag real time message
procsm0:mov ax,0 ; clear special
mov special,ax
ret ; exit
procsm endp
;--------------------------------------------------------------
; sysexc (special = 3 )
; inte processing of system exclusive values
; local call with intval in AL
;
sysexc proc near
push ax ; save inte value
call putp ; save in parameter buffer
pop ax
cmp al,0F7H ; was it EOX
jnz sysexc0 ; no, just exit
mov ax,0 ; yes,
mov _loading,ax ; clear loading flag
mov special,ax ; clear special
inc word ptr _pending ; inc pending flag
sysexc0:ret ; exit
sysexc endp
;--------------------------------------------------------------
; songsel (special = 4)
; inte processing of song select
; local call with intval in AL
;
songsel proc near
nop ; dummy routine
mov ax,0 ; clear special
mov special,ax
ret
songsel endp
;--------------------------------------------------------------
; songp1 (special = 5)
; inte processing of song position 1st byte
; local call with intval in AL
;
songp1 proc near
nop ; dummy routine
mov ax,6 ; special = 6
mov special,ax ; songp2 on next int
ret
songp1 endp
;--------------------------------------------------------------
; songp2 (special = 6)
; inte processing of position 2nd byte
; local call with intval in AL
;
songp2 proc near
nop ; dummy routine
mov ax,0 ; clear special
mov special,ax
ret
songp2 endp
;--------------------------------------------------------------
; a little beep on the speaker
;
public _beep
_beep proc far
mov al,0b6h
out 043h,al ;write timer mode regester
mov ax,1000 ;set divisor value to 1000
out 042h,al ;write timer 1 count lsb
mov al,ah
out 042h,al ;write timer 2 count msb
in al,061h ;get current port b setting
mov ah,al ;save current setting.
or al,3 ;turn speaker on
out 061h,al
mov cx,0a48h ;10 msec delay on ibm pc 4.7mh 8088
delay:
loop delay
mov al,ah ;get old port b setting
out 061h,al ;set it back the way you found it
ret
_beep endp
;--------------------------------------------------------------
; blip(char) -- sends char to upper right corner of screen
;
public _blip
_blip proc far
push bp
mov bp,sp
mov ax,[bp+p1]
add ax,'0'
mov cx,ds
mov dx,0B800H
mov ds,dx
mov byte ptr ds:9EH,al
mov ds,cx
mov sp,bp
pop bp
ret
_blip endp
;--------------------------------------------------------------
PRIM_TEXT ENDS
END
###############################################################
/**************************************************************
* midi.h
*
* equates for MPU-401 & MIDI
*
*/
/* mpu port addresses & flags
*/
#define MDATA 0x330 /* mpu data port address */
#define MSTAT 0x331 /* mpu status port address */
#define MCMD 0x331 /* mpu command port address */
#define MDSR 0x80 /* mpu data set ready, active low */
#define MDRR 0x40 /* mpu data read ready, active low */
/* general equates
*/
#define TRUE 1
#define FALSE 0
/* midi codes
*/
#define KEY_ON 0x90 /* +2, turn note on/off */
#define KEY_OFF 0x80 /* +2, turn note off */
#define EOX 0xF7 /* +0, end of transmission */
/* Yamaha specific codes
*/
#define DUMP_1V 0 /* bulk dump 1 voice */
#define DUMP_1P 1 /* bulk dump 1 performance setup */
#define DUMP_64P 2 /* bulk dump 64 performance setups */
#define DUMP_32V 9 /* bulk dump 32 voices */
#define DUMP_CA 125 /* dump condition acknowledge */
###############################################################
/**************************************************************
* testmidi.c 1/4/86 Copyright (c) 1986, John Dunn
*
* test program for MPU/MIDI and TX816
*
*/
#include "stdio.h"
#include "midi.h"
/**************************************************************
* global values
*/
extern unsigned char pbuf[]; /* play buffer */
extern unsigned char rbuf[]; /* recording buffer */
extern unsigned char sbuf[]; /* sysexc dump buffer */
extern unsigned int indexp; /* play buf index */
extern unsigned int indexr; /* recording buf index */
extern unsigned int indexs; /* sysexc dump buf index */
extern unsigned int channel; /* current midi channel */
extern unsigned int pending; /* number of sys excl pending */
extern unsigned int recording; /* nz when recording track data */
extern unsigned int playing; /* nz when playing track data */
extern unsigned int looping; /* nz when playing a loop */
extern unsigned int loading; /* nz when loading sysexc dump data */
extern unsigned int enderr; /* nz if put index at limit */
extern unsigned long ticks; /* clock tick count */
extern unsigned long nextt; /* timer tick count */
extern unsigned char tocks[]; /* midi string tick representation */
extern unsigned char packet[]; /* midi output packet */
unsigned int gv = 64; /* global note velocity */
main(argc, argv)
int argc;
char *argv[];
{
int i;
initm();
printf("starting\n");
getchar();
channel = 0;
startt();
dump_request(DUMP_1V);
for(i = 0; i < 166; ++i)
printf("%x ",sbuf[i]);
printf("\n\n");
for(i = 145+6; i < 155+6; ++i)
printf("%c",sbuf[i]);
printf("\n\n");
dump_request(DUMP_1P);
for(i = 0; i < 110; ++i)
printf("%x ",sbuf[i]);
printf("\n\n");
for(i = 64+6; i < 94+6; ++i)
printf("%c",sbuf[i]);
printf("\n");
foo();
nextt = 0;
ticks = 0;
indexp = 0;
playing = TRUE;
getchar();
looping = TRUE;
playing = TRUE;
getchar();
while(!packet[2]);
printf("ready to record\n");
indexr = 0;
recording = 1;
getchar();
indexr = 0;
for(i = 0; i < 256; ++i)
printf("%x ",rbuf[i]);
printf("\n\n");
stopt();
exitm();
getchar();
exit(0);
}
/**************************************************************
* issue a request to dump data
* specific to Yamaha
*/
dump_request(fmt)
int fmt;
{
indexs = 0;
midio(0xF0);
midio(0x43);
midio(0x20 | channel);
midio(fmt);
midio(EOX);
while(!loading);
}
/**************************************************************
* xlates(notes)
* translate a character string to midi data in the play buffer
* valid characters:
* T,S,I,Q,H,W = notes
* 0,1,2,3,4,5,6,7,8,9 = octaves
* A,B,C,D,E,F,G = pitch
* +,- = sharp, flat
*/
xlate(notes)
char *notes;
{
int time,oct,val;
char c;
playing = 0; /* disable playing */
indexp = 0; /* reset play index */
ticks = 0; /* reset clock */
while (c = toupper(*notes++))
{
if(c > 'G')
{ switch(c)
{ case 'T': time = 1; break; /* 32nd note */
case 'S': time = 2; break; /* 16th note */
case 'I': time = 4; break; /* Eighth note */
case 'Q': time = 8; break; /* quarter note */
case 'H': time = 16; break; /* half note */
case 'W': time = 32; break; /* whole note */
}
putp(KEY_ON); /* send MIDI note on */
putptok(); /* send current time */
ticks = ticks+time; /* add note time/2 */
putp(oct+val); /* send note value */
putp(gv); /* send global velocity */
putp(KEY_ON); /* send MIDI note off */
putptok();
ticks = ticks+time; /* add note time/2 */
putp(oct+val); /* send note value */
putp(0); /* send velocity = 0 */
}
else
if(c >= 'A')
{ switch(c)
{ case 'C': val = 0; break; /* key of C */
case 'D': val = 2; break;
case 'E': val = 4; break;
case 'F': val = 5; break;
case 'G': val = 7; break;
case 'A': val = 9; break;
case 'B': val = 11; break;
}
}
else
if(c >= '0')
oct = 12*(c-'0');
else
switch(c)
{ case '+': val++; break; /* sharp */
case '-': val--; break; /* flat */
}
}
indexp = 0; /* reset play index */
ticks = 0; /* reset clock */
}
/* translate ticks to tocks, then put tocks into the play buffer
*/
putptok()
{
tictoc(); /* ticks --> tocks */
putp(tocks[0]);
putp(tocks[1]);
putp(tocks[2]);
putp(tocks[3]);
}
foo()
{
static char *this =
"3CIESGS4CIESGS5CIESGS6CIESGS7CH";
xlate(this);
}